package org.example.cloudphoto.common.utils;

import org.jtransforms.dct.DoubleDCT_2D;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

@Component
public class ImageSimilarUtils {
    @Value("${opencv.dll-path}")
    private String dllPath;

    private static boolean loaded = false;

    @PostConstruct
    public void init() {
        if (!loaded) {
            System.load(dllPath);
            loaded = true;
            System.out.println("✅ OpenCV DLL 加载成功: " + dllPath);
        }
    }
    public static Mat fileToMat(File file) {
        return Imgcodecs.imread(file.getAbsolutePath());
    }

    public static Mat multipartFileToMat(MultipartFile file) {
        try {
            BufferedImage image = ImageIO.read(file.getInputStream());
            return bufferedImageToMat(image);
        } catch (IOException e) {
            throw new RuntimeException("无法解析图片", e);
        }
    }

    public static Mat urlToMat(String url) throws IOException {
        BufferedImage image = ImageIO.read(new URL(url));
        return bufferedImageToMat(image);
    }

    public static Mat bufferedImageToMat(BufferedImage bi) {
        int width = bi.getWidth();
        int height = bi.getHeight();
        Mat mat = new Mat(height, width, CvType.CV_8UC3);
        int[] data = new int[width * height];
        bi.getRGB(0, 0, width, height, data, 0, width);
        byte[] bytes = new byte[width * height * 3];

        for (int i = 0; i < data.length; i++) {
            bytes[i * 3] = (byte) ((data[i] >> 16) & 0xFF);
            bytes[i * 3 + 1] = (byte) ((data[i] >> 8) & 0xFF);
            bytes[i * 3 + 2] = (byte) (data[i] & 0xFF);
        }

        mat.put(0, 0, bytes);
        return mat;
    }

    public static String getPHash(Mat mat) {
        // 1. Resize to 32x32
        Mat resized = new Mat();
        Imgproc.resize(mat, resized, new org.opencv.core.Size(32, 32));

        // 2. Convert to grayscale
        Mat gray = new Mat();
        Imgproc.cvtColor(resized, gray, Imgproc.COLOR_BGR2GRAY);

        // 3. Convert to double array
        double[][] pixels = new double[32][32];
        for (int i = 0; i < 32; i++) {
            for (int j = 0; j < 32; j++) {
                pixels[i][j] = gray.get(i, j)[0];
            }
        }

        // 4. Do DCT
        DoubleDCT_2D dct = new DoubleDCT_2D(32, 32);
        dct.forward(pixels, true);

        // 5. Extract top-left 8x8
        double total = 0.0;
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                total += pixels[i][j];
            }
        }
        double avg = total / 64.0;

        // 6. Hash: 64-bit binary string
        StringBuilder hash = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                hash.append(pixels[i][j] > avg ? '1' : '0');
            }
        }

        return hash.toString(); // 长度为64
    }

    public static int hammingDistance(String hash1, String hash2) {
        int distance = 0;
        for (int i = 0; i < hash1.length(); i++) {
            if (hash1.charAt(i) != hash2.charAt(i)) {
                distance++;
            }
        }
        return distance;
    }

}
